﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;

namespace Liquid.Windows {
	[ProvideProperty("WatermarkText", typeof(ToolStripTextBox))]
	[ProvideProperty("WatermarkForeColor", typeof(ToolStripTextBox))]
	[ProvideProperty("WatermarkBackColor", typeof(ToolStripTextBox))]
	public class WatermarkProvider : Component, IExtenderProvider {
		public bool CanExtend(object extendee) {
			return extendee is TextBoxBase
				|| extendee is ToolStripTextBox;
		}

		class WatermarkInfo {
			public Color NormalForeColor;
			public Color NormalBackColor;

			public string WatermarkText;
			public Color? WatermarkForeColor;
			public Color? WatermarkBackColor;
			public bool WatermarkActive;

			public bool IsEmpty {
				get {
					return WatermarkText == null
						&& WatermarkForeColor == null
						&& WatermarkBackColor == null;
				}
			}
			public Color ForeColor {
				get {
					return WatermarkActive
						? (WatermarkForeColor ?? NormalForeColor)
						: NormalForeColor;
				}
			}
			public Color BackColor {
				get {
					return WatermarkActive
						? (WatermarkBackColor ?? NormalBackColor)
						: NormalBackColor;
				}
			}
		}

		Dictionary<object, WatermarkInfo> watermarks = new Dictionary<object, WatermarkInfo>();

		public void ClearWatermark(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (watermarks.TryGetValue(toolStripTextBox, out info))
				RemoveFrom(toolStripTextBox, info);
		}

		public string GetWatermarkText(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info))
				return null;
			else
				return info.WatermarkText;
		}
		public void SetWatermarkText(ToolStripTextBox toolStripTextBox, string value) {
			if (value == null) { ResetWatermarkText(toolStripTextBox); return; }
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info)) {
				info = AddTo(toolStripTextBox);
			}
			info.WatermarkText = value;
			Update(toolStripTextBox, info);
		}
		public bool ShouldSerializeWatermarkText(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info))
				return false;
			else
				return !string.IsNullOrEmpty(info.WatermarkText);
		}
		public void ResetWatermarkText(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (watermarks.TryGetValue(toolStripTextBox, out info)) {
				info.WatermarkText = null;
				if (info.IsEmpty)
					RemoveFrom(toolStripTextBox, info);
				Update(toolStripTextBox, info);
			}
		}

		public Color GetWatermarkForeColor(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info))
				return toolStripTextBox.ForeColor;
			else
				return info.WatermarkForeColor ?? toolStripTextBox.ForeColor;
		}
		public void SetWatermarkForeColor(ToolStripTextBox toolStripTextBox, Color value) {
			if (value == null) { ResetWatermarkForeColor(toolStripTextBox); return; }
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info)) {
				info = AddTo(toolStripTextBox);
			}
			info.WatermarkForeColor = value;
			Update(toolStripTextBox, info);
		}
		public bool ShouldSerializeWatermarkForeColor(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info))
				return false;
			else
				return info.WatermarkForeColor != null;
		}
		public void ResetWatermarkForeColor(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (watermarks.TryGetValue(toolStripTextBox, out info)) {
				info.WatermarkForeColor = null;
				if (info.IsEmpty)
					RemoveFrom(toolStripTextBox, info);
				Update(toolStripTextBox, info);
			}
		}

		public Color GetWatermarkBackColor(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info))
				return toolStripTextBox.BackColor;
			else
				return info.WatermarkBackColor ?? toolStripTextBox.BackColor;
		}
		public void SetWatermarkBackColor(ToolStripTextBox toolStripTextBox, Color value) {
			if (value == null) { ResetWatermarkBackColor(toolStripTextBox); return; }
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info)) {
				info = AddTo(toolStripTextBox);
			}
			info.WatermarkBackColor = value;
			Update(toolStripTextBox, info);
		}
		public bool ShouldSerializeWatermarkBackColor(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (!watermarks.TryGetValue(toolStripTextBox, out info))
				return false;
			else
				return info.WatermarkBackColor != null;
		}
		public void ResetWatermarkBackColor(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info;
			if (watermarks.TryGetValue(toolStripTextBox, out info)) {
				info.WatermarkBackColor = null;
				if (info.IsEmpty)
					RemoveFrom(toolStripTextBox, info);
				Update(toolStripTextBox, info);
			}
		}

		private WatermarkInfo AddTo(ToolStripTextBox toolStripTextBox) {
			WatermarkInfo info = new WatermarkInfo {
				NormalForeColor = toolStripTextBox.ForeColor,
				NormalBackColor = toolStripTextBox.BackColor,
			};
			toolStripTextBox.Enter += new EventHandler(toolStripTextBox_Enter);
			toolStripTextBox.Leave += new EventHandler(toolStripTextBox_Enter);
			watermarks.Add(toolStripTextBox, info);
			return info;
		}
		private void RemoveFrom(ToolStripTextBox toolStripTextBox, WatermarkInfo info) {
			toolStripTextBox.Enter -= new EventHandler(toolStripTextBox_Enter);
			toolStripTextBox.Leave -= new EventHandler(toolStripTextBox_Enter);
			info.WatermarkText = null;
			info.WatermarkForeColor = null;
			info.WatermarkBackColor = null;
			Update(toolStripTextBox, info);
		}

		void toolStripTextBox_Enter(object sender, EventArgs e) {
			Update((ToolStripTextBox)sender);
		}
		void toolStripTextBox_Leave(object sender, EventArgs e) {
			Update((ToolStripTextBox)sender);
		}
		private void Update(ToolStripTextBox toolStripTextBox) {
			Update(toolStripTextBox, watermarks[toolStripTextBox]);
		}
		private void Update(ToolStripTextBox toolStripTextBox, WatermarkInfo info) {
			if (DesignMode)
				return;
			if (toolStripTextBox.Focused) {
				if (info.WatermarkActive)
					toolStripTextBox.Text = "";
				info.WatermarkActive = false;
				toolStripTextBox.ForeColor = info.NormalForeColor;
				toolStripTextBox.BackColor = info.NormalBackColor;
			} else {
				if (info.WatermarkActive == false || toolStripTextBox.Text == "") {
					info.WatermarkActive = true;
					toolStripTextBox.Text = info.WatermarkText;
					toolStripTextBox.ForeColor = info.ForeColor;
					toolStripTextBox.BackColor = info.BackColor;
				} else {
					info.WatermarkActive = false;
				}
			}
		}
	}
}
